package com.violet.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.violet.domain.emuns.OrderPriceGroupBy;
import com.violet.domain.emuns.OrderStatus;
import com.violet.domain.po.BuyOrder;
import com.violet.domain.po.Product;
import com.violet.domain.po.User;
import com.violet.domain.result.StatisticalData;
import com.violet.mapper.BuyOrderMapper;
import com.violet.mapper.ProductMapper;
import com.violet.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

@Component
@RequiredArgsConstructor
public class StatisticsUtils {

    private final BuyOrderMapper buyOrderMapper;
    private final UserMapper userMapper;
    private final ProductMapper productMapper;

    public StatisticalData generate() {
        StatisticalData statisticalData = new StatisticalData();
        // 1.获取今日下单数、今日下单数与昨日下单数的增长度、今日销售额、今日与昨日销售额的增长度
        this.setOrderData(statisticalData);
        // 2.获取今日注册用户数、今日注册用户数与昨日注册用户数的增长度
        this.setUserData(statisticalData);
        // 3.获取营业额数据
        this.setPriceData(statisticalData);
        // 4.设置热门商品
        this.setHotProducts(statisticalData);
        // 5.统计库存不足 20 的商品数
        this.setOutStockProductCount(statisticalData);
        // 返回数据
        return statisticalData;
    }

    // 获取订单数据统计：【今日下单数、今日下单数与昨日下单数的增长度、今日销售额、今日与昨日销售额的增长度】
    private void setOrderData(StatisticalData data) {
        // 获取昨日的订单（不包含今天）
        List<BuyOrder> yesterdayOrders = buyOrderMapper.selectList(
            new LambdaQueryWrapper<BuyOrder>()
                .eq(BuyOrder::getStatus, OrderStatus.COMPLETED)
                .lt(BuyOrder::getOrderTime, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0))
                .ge(BuyOrder::getOrderTime, LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0))
        );
        // 今日订单完成的订单数
        List<BuyOrder> todayOrders = buyOrderMapper.selectList(
            new LambdaQueryWrapper<BuyOrder>()
                .eq(BuyOrder::getStatus, OrderStatus.COMPLETED)
                .ge(BuyOrder::getOrderTime, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0))
        );
        // 差值百分比
        double todayOrderCountPercentage = this.getPercentage(yesterdayOrders.size(), todayOrders.size());
        // 设置数据
        data.setTodayOrderCount(todayOrders.size()).setTodayOrderCountPercentage(todayOrderCountPercentage);

        // 2.统计昨日今日销售额
        double todayTotalPrice = todayOrders.stream().mapToDouble(BuyOrder::getFinalPrice).sum();
        double yesterdayTotalPrice = yesterdayOrders.stream().mapToDouble(BuyOrder::getFinalPrice).sum();
        // 差值百分比
        double todayTotalPricePercentage = this.getPercentage(yesterdayTotalPrice, todayTotalPrice);
        // 设置数据
        data.setTodayTotalPrice(todayTotalPrice).setTodayTotalPricePercentage(todayTotalPricePercentage);
    }

    // 获取用户数据统计：【今日注册用户数、今日注册用户数与昨日注册用户数的增长度】
    private void setUserData(StatisticalData data) {
        // 昨日注册用户数量
        Long yesterdayRegisterUserCount = userMapper.selectCount(
            new LambdaQueryWrapper<User>()
                .lt(User::getCreateTime, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0))
                .ge(User::getCreateTime, LocalDateTime.now().minusDays(1).withHour(0).withMinute(0).withSecond(0))
        );
        // 今日注册用户数量
        Long todayRegisterUserCount = userMapper.selectCount(
            new LambdaQueryWrapper<User>()
                .ge(User::getCreateTime, LocalDateTime.now().withHour(0).withMinute(0).withSecond(0))
        );
        // 差值百分比
        double todayRegisterUserCountPercentage = this.getPercentage(yesterdayRegisterUserCount, todayRegisterUserCount);
        // 设置数据
        data.setTodayRegisterUserCount(todayRegisterUserCount).setTodayRegisterUserCountPercentage(todayRegisterUserCountPercentage);
    }

    // 获取营业额数据
    private void setPriceData(StatisticalData data) {
        data.setWeekDayPrice(this.getWeekDayPrice());
        data.setMonthDayPrice(this.getMonthDayPrice());
        data.setYearMonthPrice(this.getYearMonthPrice());
    }

    // 获取热门商品数据
    private void setHotProducts(StatisticalData data) {
        List<Product> hotProducts = productMapper.selectList(
            new LambdaQueryWrapper<Product>()
                .orderByDesc(Product::getMonthlySales)
                .last("limit 10")
        );
        data.setHotProducts(hotProducts);
    }

    // 统计不足 20 的商品数
    private void setOutStockProductCount(StatisticalData data) {
        Long outStock = productMapper.selectCount(new LambdaQueryWrapper<Product>().le(Product::getStock, 20));
        data.setTodayOutStockProductCount(outStock);
    }

    // 获取当前周每一天的营业额
    private List<Double> getWeekDayPrice() {
        // 获取到到本周周一 和 周日的日期
        LocalDateTime monday = LocalDateTime.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDateTime sunday = LocalDateTime.now().with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        return this.getDateRangePrice(monday, sunday, OrderPriceGroupBy.DAY);
    }

    // 获取当前月，每一天的营业额
    private List<Double> getMonthDayPrice() {
        // 获取到本月第一天 和 最后一天
        LocalDateTime firstDay = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth());
        LocalDateTime lastDay = LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth());
        return this.getDateRangePrice(firstDay, lastDay, OrderPriceGroupBy.DAY);
    }

    private List<Double> getYearMonthPrice() {
        // 获取到本年第一天 和 最后一天
        LocalDateTime firstDay = LocalDateTime.now().with(TemporalAdjusters.firstDayOfYear());
        LocalDateTime lastDay = LocalDateTime.now().with(TemporalAdjusters.lastDayOfYear());
        return this.getDateRangePrice(firstDay, lastDay, OrderPriceGroupBy.MONTH);
    }

    // 获取指定日期范围内的营业额
    private List<Double> getDateRangePrice(LocalDateTime start, LocalDateTime end, OrderPriceGroupBy groupBy) {
        List<Double> result = new ArrayList<>();
        List<Map<String, Object>> maps = buyOrderMapper.selectMaps(
            new QueryWrapper<BuyOrder>()
                .select("%s(order_time) as day, SUM(final_price) as price".formatted(groupBy.value))
                .eq("status", OrderStatus.COMPLETED)
                .between("order_time", start, end)
                .groupBy("%s(order_time)".formatted(groupBy.value))
        );
        if (groupBy == OrderPriceGroupBy.DAY) {
            for (LocalDateTime day = start; !day.isAfter(end); day = day.plusDays(1)) {
                pushPrice(day.getDayOfMonth(), result, maps);
            }
        }
        else if (groupBy == OrderPriceGroupBy.MONTH) {
            for (int day = 1; day <= 12; day++) {
                pushPrice(day, result, maps);
            }
        }
        return result;
    }

    // 获取两个日期之间的增长度
    private double getPercentage(double yesterday, double today) {
        // 如果昨天的数据都是 0，并且今天的数据不是 0，那么增长度一定是 100%
        if (yesterday == 0 && today != 0) return 100;
        // 如果昨天是 0 今天也是 0，那么增长度为 0
        if (today == 0 && yesterday == 0) return 0;
        // 如果昨天不是 0，今天也不是 0，那么增长度为 ((今日 - 昨天) / 昨天) * 100
        return ((today - yesterday) / yesterday) * 100;
    }

    private void pushPrice(Integer key, List<Double> prices, List<Map<String, Object>> maps) {
        List<Object> list = maps.stream()
            .filter(map -> key.equals(map.get("day")))
            .map(map -> map.get("price"))
            .toList();

        if (!list.isEmpty()) {
            BigDecimal decimal = (BigDecimal) list.get(0);
            String string = decimal.toString();
            prices.add(Double.parseDouble(string));
        }
        else prices.add(0d);
    }

}
